home *** CD-ROM | disk | FTP | other *** search
/ Mac Easy 2010 May / Mac Life Ubuntu.iso / casper / filesystem.squashfs / usr / share / pyshared / Onboard / Keyboard.py < prev    next >
Encoding:
Python Source  |  2008-03-03  |  11.0 KB  |  345 lines

  1. #!/usr/bin/python
  2.  
  3. import gtk
  4. import gobject
  5. import gconf
  6. import string
  7.  
  8. from KeyGtk import *
  9. import KeyCommon
  10.  
  11. sidebarWidth = 60
  12. try:
  13.     from Onboard.utils import run_script, keysyms
  14. except DeprecationWarning:
  15.     pass
  16.  
  17.  
  18. class Keyboard(gtk.DrawingArea):
  19.     "Cairo based keyboard widget"
  20.     def __init__(self,sok):
  21.         gtk.DrawingArea.__init__(self)
  22.  
  23.         # This is done so multiple keys with the same modifier don't interfere with each other
  24.         self.mods = {1:0,2:0, 4:0,8:0, 16:0,32:0,64:0,128:0}
  25.  
  26.         self.add_events(gtk.gdk.BUTTON_PRESS_MASK | gtk.gdk.BUTTON_RELEASE_MASK | gtk.gdk.LEAVE_NOTIFY_MASK) 
  27.         self.connect("expose_event", self.expose)
  28.         self.connect("button_press_event", self.mouse_button_press)
  29.         self.connect("button_release_event", self.mouse_button_release)
  30.         self.connect("leave-notify-event", self.cb_leave_notify)
  31.     
  32.         self.sok = sok
  33.  
  34.         self.activePane = None 
  35.         # When set to a pane, the pane overlays the basePane.
  36.             
  37.         self.active = None #Currently active key
  38.  
  39.         self.scanning = False;
  40.         self.scanningInterval = 1;
  41.         
  42.         self.scanningActive = None # Key currently being scanned.
  43.         
  44.         self.stuck = [] 
  45.         #List of keys which have been latched.  
  46.         #ie. pressed until next non sticky button is pressed.
  47.  
  48.         self.altLocked = False 
  49.  
  50.         self.tabKeys = []
  51.  
  52.         self.panes = [] # All panes except the basePane
  53.  
  54.         self.tabKeys.append(BaseTabKey(self,sidebarWidth))
  55.  
  56.         self.queue_draw()
  57.         
  58.        
  59.     def set_basePane(self, basePane):
  60.     self.basePane = basePane #Pane which is always visible
  61.  
  62.     def add_pane(self, pane):
  63.         self.panes.append(pane)
  64.         self.tabKeys.append(TabKey(self,sidebarWidth,pane))
  65.  
  66.     def cb_leave_notify(self, widget, grabbed):
  67.         gtk.gdk.pointer_ungrab() # horrible.  Grabs pointer when key is pressed, released when cursor leaves keyboard
  68.     if self.active:
  69.                 
  70.         if self.scanningActive:
  71.             self.active = None        
  72.             self.scanningActive = None
  73.         else:        
  74.             self.release_key(self.active)
  75.         self.queue_draw()
  76.     return True
  77.     
  78.     
  79.     def utf8_to_unicode(self,utf8Char):
  80.         return ord(utf8Char.decode('utf-8'))
  81.       
  82.         
  83.     def scan_tick(self): #at intervals scans across keys in the row and then down columns.
  84.         if self.scanningActive:
  85.             self.scanningActive.beingScanned = False
  86.         
  87.         if self.activePane:
  88.             pane = self.activePane
  89.         else:
  90.             pane = self.basePane
  91.         
  92.         if not self.scanningNoY == None:
  93.             self.scanningNoY = (self.scanningNoY + 1) % len(pane.columns[self.scanningNoX])
  94.         else:
  95.             self.scanningNoX = (self.scanningNoX + 1) % len(pane.columns)
  96.         
  97.         if self.scanningNoY == None:
  98.             y = 0
  99.         else:
  100.             y = self.scanningNoY
  101.         
  102.         self.scanningActive = pane.columns[self.scanningNoX][y]
  103.         
  104.         self.scanningActive.beingScanned = True
  105.      self.queue_draw()
  106.         
  107.         return True
  108.         
  109.     
  110.     def reset_scan(self):#Between scans and when value of scanning changes.
  111.         
  112.         if self.scanningActive:
  113.             self.scanningActive.beingScanned = False
  114.         
  115.         self.scanningTimeId = None
  116.             
  117.             self.scanningNoX = None
  118.             self.scanningNoY = None
  119.             self.queue_draw()
  120.         
  121.     def mouse_button_press(self,widget,event):
  122.         gtk.gdk.pointer_grab(self.window, True)
  123.         if event.type == gtk.gdk.BUTTON_PRESS:
  124.             self.active = None#is this doing anything
  125.             
  126.             if self.scanning and self.basePane.columns:
  127.                 
  128.                 if self.scanningTimeId:
  129.                     if not self.scanningNoY == None:
  130.                         self.press_key(self.scanningActive)
  131.                         gobject.source_remove(self.scanningTimeId)
  132.                         self.reset_scan()
  133.                     else:
  134.                         self.scanningNoY = -1
  135.                         gobject.source_remove(self.scanningTimeId)
  136.                         self.scanningTimeId = gobject.timeout_add(
  137.                                         self.scanningInterval, self.scan_tick)
  138.                 else:    
  139.                     self.scanningTimeId = gobject.timeout_add(
  140.                                         self.scanningInterval,self.scan_tick)
  141.                     self.scanningNoX = -1
  142.             else:
  143.                 if self.activePane:
  144.                     for key in self.activePane.keys.values():
  145.                         self.is_key_pressed(key, widget, event)
  146.                 else:    
  147.                     for key in self.basePane.keys.values():
  148.                         self.is_key_pressed(key, widget, event)
  149.  
  150.                 for key in self.tabKeys:
  151.                     self.is_key_pressed(key, widget, event)
  152.     return True 
  153.  
  154.      
  155.     def is_key_pressed(self,key, widget, event):
  156.         if(key.pointWithinKey(widget, event.x, event.y)):
  157.             self.press_key(key)
  158.     
  159.     def mouse_button_release(self,widget,event):
  160.         if self.active:
  161.             #self.active.on = False
  162.             self.release_key(self.active)
  163.             if len(self.stuck) > 0:
  164.                 for stick in self.stuck:
  165.                     self.release_key(stick)
  166.                 self.stuck = []
  167.             self.active = None
  168.  
  169.         self.queue_draw()
  170.         return True
  171.  
  172.     def press_key(self, key):
  173.         if not key.on:
  174.             if self.mods[8]:
  175.                 self.altLocked = True
  176.                 self.sok.vk.lock_mod(8)    
  177.  
  178.             if key.sticky == True:
  179.                     self.stuck.append(key)
  180.                     
  181.             else:
  182.                 self.active = key #Since only one non-sticky key can be pressed at once.
  183.             
  184.             key.on = True
  185.             
  186.             self.locked = []
  187.             if key.action_type == KeyCommon.CHAR_ACTION:
  188.                 self.sok.vk.press_unicode(self.utf8_to_unicode(key.action))
  189.             
  190.             elif key.action_type == KeyCommon.KEYSYM_ACTION:
  191.                 self.sok.vk.press_keysym(key.action)
  192.             
  193.             elif key.action_type == KeyCommon.MODIFIER_ACTION:
  194.                 mod = key.action
  195.                 
  196.                 if not mod == 8: #Hack since alt puts metacity into move mode and prevents clicks reaching widget.
  197.                     self.sok.vk.lock_mod(mod)
  198.                 self.mods[mod] += 1
  199.                     
  200.  
  201.             elif key.action_type == KeyCommon.MACRO_ACTION:
  202.                 try:
  203.                     mString = self.sok.macros[string.atoi(key.action)]
  204.                     if mString:#If mstring exists do the below, otherwise the code in finally should always be done.
  205.                         for c in mString:
  206.                             char = self.utf8_to_unicode(c)
  207.                             self.sok.vk.press_unicode(char)
  208.                             self.sok.vk.release_unicode(char)
  209.                         return
  210.                             
  211.                 except IndexError:
  212.                     pass
  213.  
  214.                 dialog = gtk.Dialog("No snippet", self.sok.window, 0, ("_Save snippet", gtk.RESPONSE_OK, 
  215.                                         "_Cancel", gtk.RESPONSE_CANCEL))
  216.                 dialog.vbox.add(gtk.Label("No snippet for this button,\nType new snippet"))
  217.                 
  218.                 macroEntry = gtk.Entry()                
  219.             
  220.                 dialog.connect("response", self.cb_dialog_response,string.atoi(key.action), macroEntry)
  221.                 
  222.                 macroEntry.connect("activate", self.cb_macroEntry_activate,string.atoi(key.action), dialog)
  223.                 dialog.vbox.pack_end(macroEntry)
  224.  
  225.                 dialog.show_all()
  226.  
  227.             elif key.action_type == KeyCommon.KEYCODE_ACTION:
  228.                 self.sok.vk.press_keycode(key.action);
  229.                 
  230.             elif key.action_type == KeyCommon.SCRIPT_ACTION:
  231.                 run_script(key.action, self.sok)    
  232.                 
  233.             else:
  234.                 for k in self.tabKeys: # don't like this.
  235.                     if k.pane == self.activePane:
  236.                         k.on = False
  237.                         k.stuckOn = False
  238.                 
  239.                 self.activePane = key.pane
  240.         else:
  241.             if key in self.stuck:
  242.                 key.stuckOn = True
  243.                 self.stuck.remove(key)
  244.             else:
  245.                 key.stuckOn = False
  246.                 self.release_key(key)
  247.  
  248.         self.queue_draw()
  249.             
  250.         
  251.     def cb_dialog_response(self, widget, response, macroNo,macroEntry):
  252.     self.set_new_macro(macroNo, response, macroEntry, widget)
  253.  
  254.     def cb_macroEntry_activate(self,widget,macroNo,dialog):
  255.     self.set_new_macro(macroNo, gtk.RESPONSE_OK, widget, dialog)
  256.     
  257.         
  258.  
  259.     def set_new_macro(self,macroNo,response,macroEntry,dialog):
  260.     if response == gtk.RESPONSE_OK:    
  261.         
  262.         if macroNo > (len(self.sok.macros) - 1):#makes sure array long enough for this next bit
  263.             for n in range((macroNo + 1) - len(self.sok.macros)):            
  264.                 self.sok.macros.append("")
  265.         
  266.         self.sok.macros[macroNo] = macroEntry.get_text()
  267.         self.sok.gconfClient.set_list("/apps/sok/macros",gconf.VALUE_STRING, self.sok.macros)
  268.  
  269.     dialog.destroy()
  270.     
  271.     def release_key(self,key):
  272.         if key.action_type == KeyCommon.CHAR_ACTION:
  273.             self.sok.vk.release_unicode(self.utf8_to_unicode(key.action))
  274.         elif key.action_type == KeyCommon.KEYSYM_ACTION:
  275.             self.sok.vk.release_keysym(key.action)
  276.         elif key.action_type == KeyCommon.MODIFIER_ACTION:
  277.             mod = key.action
  278.             
  279.             if not mod == 8:        
  280.                 self.sok.vk.unlock_mod(mod)
  281.             
  282.             self.mods[mod] -= 1
  283.             
  284.         elif key.action_type == KeyCommon.KEYCODE_ACTION:
  285.             self.sok.vk.release_keycode(key.action);
  286.             
  287.         elif (key.action_type == KeyCommon.MACRO_ACTION or 
  288.               key.action_type == KeyCommon.SCRIPT_ACTION):
  289.             pass
  290.                 
  291.                 
  292.         else:
  293.             self.activePane = None
  294.         
  295.         
  296.         if self.altLocked:
  297.             self.altLocked = False
  298.             self.sok.vk.unlock_mod(8)
  299.         
  300.         gobject.idle_add(self.release_key_idle,key) #Makes sure we draw key pressed before unpressing it. 
  301.  
  302.  
  303.     def release_key_idle(self,key):
  304.         key.on = False
  305.         self.queue_draw()
  306.         return False
  307.  
  308.           
  309.     
  310.     def expose(self, widget, event):
  311.         
  312.         context = widget.window.cairo_create()
  313.         context.set_line_width(1.1)
  314.  
  315.         size = self.get_allocation()
  316.  
  317.         self.kbwidth = size.width - sidebarWidth # to allow for sidebar
  318.         self.height = size.height
  319.  
  320.         context.set_source_rgba(float(self.basePane.rgba[0]),
  321.                     float(self.basePane.rgba[1]),
  322.                     float(self.basePane.rgba[2]),
  323.                     float(self.basePane.rgba[3]))#get from .sok
  324.         context.paint()
  325.  
  326.  
  327.         self.basePane.paint(context,self.kbwidth,self.height)
  328.  
  329.         if (self.activePane):
  330.  
  331.             context.rectangle(0, 0, self.kbwidth, self.height)
  332.             context.set_source_rgba(float(self.activePane.rgba[0]),
  333.                         float(self.activePane.rgba[1]),
  334.                         float(self.activePane.rgba[2]),
  335.                         float(self.activePane.rgba[3]))#get from .sok
  336.             context.fill()
  337.             self.activePane.paint(context,self.kbwidth,self.height)
  338.  
  339.             
  340.             
  341.         for key in self.tabKeys:
  342.             key.paint(context)
  343.  
  344.         return True
  345.